package com.sinodata.bsm.cicp.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.sinodata.bsm.common.vo.ProtocolParameter;

/**
 * 
 * <p>
 * Description: 采集程序util类
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-11-23 9:57:04       liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class CollectorUtil {

    // 缺省超时时间,单位:秒
    private final static int DEFAULT_TIMEOUT = 60;
    private final static int SECOND = 1000;
    private static Logger logger = Logger.getLogger("prop");
    private static Logger cmdLogger = Logger.getLogger("prop");
    private static String localIP = null;
    private static int defaultCmdPort = 9001;

    private static Pattern fileLinePattern = null;
    private static Pattern fileLinePatternWin = null;
    //private static PatternMatcher matcher = new Perl5Matcher();
    private static Matcher matcher = null;

    private static final String DATE_FORMATE = "yyyy-MM-dd HH:mm:ss";

    private static final String CMDSERVER = "cmdserver"; // cmdserver采集方式
    private static final String TELNET = "telnet"; // telnet采集方式
    private static final String SSH = "ssh"; // ssh采集方式
    private static final String SSH2 = "ssh2"; // ssh2采集方式

    private static final int URL_CONN_TIME_OUT = 15000;

    static {
        try {
            String fileLinePatternStr =
            // "(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\S+)+\\s+(\\d+)\\s+(\\S+\\s+\\d+\\s+\\S+)\\s+(\\S+)";
            "(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\S+)+\\s+(\\d+)\\s+(.+)\\s+(\\S+)";
            String fileLinePatternStrWin = "(.+)#\\d+#NONE#(\\S+)#\\S+#(\\d+)#(\\S+)#(\\S+)#(\\d+)#(\\S+)#\\S+#\\S+#\\d+#NONE";
            /*PatternCompiler compiler = new Perl5Compiler();
            fileLinePattern = compiler.compile(fileLinePatternStr);
            fileLinePatternWin = compiler.compile(fileLinePatternStrWin);*/
            fileLinePattern = Pattern.compile(fileLinePatternStr);
            fileLinePatternWin = Pattern.compile(fileLinePatternStrWin);
        } catch (Exception ex) {
            logger.error("Wrong login line pattern", ex);
        }
    }

    /**
     * 设置默认的cmdserver端口
     *
     * @param p
     *            int 默认端口
     */
    public static void setDefaultCmdPort(int p) {
        defaultCmdPort = p;
    }

    /**
     * 执行本的命令，获取process的输入流
     *
     * @param cmd
     * @return BufferedReader process的输入流
     * @throws IOException
     */
    public static BufferedReader getLocalReader(String cmd) throws IOException {
        return getReader(cmd, getLocalhostIp());
    }

    private static String getLocalhostIp() {
        if (localIP == null) {
            try {
                localIP = InetAddress.getLocalHost().getHostAddress().toString();
            } catch (UnknownHostException e) {
                localIP = "localhost";
            }
        }
        return localIP;
    }

    /**
     * 通过默认端口执行指定ip上的命令，得到输出流
     *
     * @param cmdstr
     *            String 执行的命令
     * @param ip
     *            String IP地址
     * @return BufferedReader 输出流
     * @throws IOException
     */
    public static BufferedReader getReader(String cmdstr, String ip) throws IOException {
        return getReader(cmdstr, ip, DEFAULT_TIMEOUT);
    }

    /**
     * 根据cmdstr创建一个进程,并将该进程的输出流返回
     *
     * @param cmdstr
     *            String 执行的命令
     * @param ip
     *            String IP地址
     * @param timeout
     *            int 超时时间间隔，单位:秒
     * @return 输出流
     * @throws IOException
     */
    public static BufferedReader getReader(String cmdstr, String ip, int timeout) throws IOException {
        return null;
    }

    public static List getResultFromCommand(String cmdStr, String rowSeperator, String fieldSeperator) {
        throw new java.lang.IllegalAccessError("not implemented");
    }

    /**
     * 执行cmdStr所代表的命令, 将执行结果中,匹配ptnStr每一行数据返回
     * 返回结果中,List的每个元素为一个符合匹配串(contains,不是match)的行;
     * 返回结果中,List的每个元素为String[]数组.该数组的每个元素为正则表达式的一个group
     * 返回结果中,List中的每个元素不可能为null,但String[]的length可能为0
     * 如果命令执行不成功,或者整个过程出现异常,则返回的list的size()为0;
     *
     * @param cmdStr
     * @param ptnStr
     * @return
     */
    public static List getMatchResultFromCommand(String cmdStr, String ptnStr, String ip) {
        List retList = new ArrayList();
        if (cmdStr == null)
            return retList;
        String[] aLine = null;
        // PatternMatcher pm = new Perl5Matcher();
        // PatternCompiler compiler = new Perl5Compiler();
        Matcher pm = null;
        Pattern pattern = null;
        MatchResult matchResult = null;
        // reader读入的每行数据
        String strLine = null;
        BufferedReader reader = null;
        // 获取输入流
        try {
            reader = CollectorUtil.getReader(cmdStr, ip, DEFAULT_TIMEOUT);
            if (reader == null) {
                return retList;
            }
            // pattern = compiler.compile(ptnStr);
            pattern = Pattern.compile(ptnStr);
            while (true) {
                try {
                    strLine = reader.readLine(); // ------ERROR!可能死循环
                } catch (Throwable t) {
                    logger.error(t);
                    break;
                }
                /* if (strLine == null) {
                     break;
                 } else if (pm.contains(strLine, pattern)) { // 匹配了一行
                     matchResult = pm.getMatch();
                     aLine = new String[matchResult.groups()];
                     for (int i = 0; i < aLine.length; i++) {
                         aLine[i] = matchResult.group(i);
                     }
                     retList.add(aLine);
                 }*/
                if (strLine == null) {
                    break;
                } else {
                    pm = pattern.matcher(strLine);
                    if (pm.find()) {
                        matchResult = pm.toMatchResult();
                        aLine = new String[matchResult.groupCount()];
                        for (int i = 0; i < aLine.length; i++) {
                            aLine[i] = matchResult.group(i);
                        }
                        retList.add(aLine);
                    }
                }
            }
        } catch (Throwable t) {
            logger.error(t);
        } finally {
            pm = null;
            // compiler = null;
            matchResult = null;
            aLine = null;
            if (reader != null) {
                try {
                    reader.close();
                } catch (Throwable t) {
                    t.getMessage();
                }
            }
        }
        return retList;
    }

    /**
     * 执行cmdStr所代表的命令, 将执行结果中,匹配ptnStr每一行数据作为一个matchResult返回
     * 返回结果中,List的每个元素为一个符合匹配串(contains,不是match)的行;
     * 返回结果中,List的每个元素为String[]数组.该数组的每个元素为正则表达式的一个group
     * 返回结果中,List中的每个元素不可能为null,但String[]的length可能为0
     * 如果命令执行不成功,或者整个过程出现异常,则返回的list的size()为0;
     *
     * @param cmdStr
     * @param ptnStr
     * @return
     */
    public static List getMatchGroupFromCommand(String cmdStr, String ptnStr, String ip) {
        List retList = new ArrayList();
        if (cmdStr == null)
            return retList;
        //        String[] aLine = null;
        // PatternMatcher pm = new Perl5Matcher();
        // PatternCompiler compiler = new Perl5Compiler();
        Matcher pm = null;
        Pattern pattern = null;
        MatchResult matchResult = null;
        // reader读入的每行数据
        String strLine = null;
        BufferedReader reader = null;
        // 获取输入流
        try {
            reader = CollectorUtil.getReader(cmdStr, ip, DEFAULT_TIMEOUT);
            // pattern = compiler.compile(ptnStr);
            pattern = Pattern.compile(ptnStr);
            while (true) {
                try {
                    strLine = reader.readLine();
                } catch (Throwable t) {
                    logger.error(t);
                    break;
                }
                /*if (strLine == null) {
                    break;
                } else if (pm.contains(strLine, pattern)) { // 匹配了一行
                    matchResult = pm.getMatch();
                    retList.add(matchResult);
                }*/
                if (strLine == null) {
                    break;
                } else {
                    pm = pattern.matcher(strLine);
                    matchResult = pm.toMatchResult();
                    retList.add(matchResult);
                }
            }
        } catch (Throwable t) {
            logger.error(t);
        } finally {
            pm = null;
            ///compiler = null;
            matchResult = null;
            //            aLine = null;
            if (reader != null) {
                try {
                    reader.close();
                } catch (Throwable t) {
                    t.getMessage();
                }
            }
        }
        return retList;
    }

    /**
     * 获取cmdStr的运行结果,以List of String形式返回
     *
     * @param cmdStr
     * @return
     */
    public static List<String> getResultStrFromCommand(String cmdStr, String ip) {
        List<String> retList = new ArrayList<String>();
        if (cmdStr == null)
            return retList;
        //        String[] aLine = null;
        // reader读入的每行数据
        String strLine = null;
        BufferedReader reader = null;
        // 获取输入流
        try {
            reader = CollectorUtil.getReader(cmdStr, ip, DEFAULT_TIMEOUT);
            while (true) {
                try {
                    strLine = reader.readLine();
                } catch (Throwable t) {
                    logger.error(t);
                    break;
                }
                if (strLine == null) {
                    break;
                }
                retList.add(strLine);
            }
        } catch (Throwable t) {
            logger.error(t);
        } finally {
            //            aLine = null;
            if (reader != null) {
                try {
                    reader.close();
                } catch (Throwable t) {
                    logger.error(t);
                }
            }
        }
        return retList;
    }

    /**
     * 得到一个目录中文件名匹配某个模式的文件中最新的文件
     *
     * @param path
     *            目录名
     * @param pattern
     *            文件名模式
     * @param ip
     *            主机的IP
     * @return 满足要求的文件的属性，或者当不存在这样的文件时NULL
     */
    public static FileAttribute getNewestRemoteFileByPattern(String path, String filterDir, String pattern, String ip) {
        //wangpeng add all
        String cmd = "";
        FileAttribute currentAttribute = null;
        if (filterDir != null && !filterDir.equals("")) {
            filterDir = filterDir.trim();
            if (!filterDir.endsWith("/")) {
                filterDir += "/";
            }
            cmd = "ls -lt " + path + " |" + filterDir + "filter -p \"" + pattern + "\" | head -n 1";
        } else {
            cmd = "ls -lt " + path + " |filter -p \"" + pattern + "\" | head -n 1";
        }
        // String regex = "(.).{9}\\s+(\\d+)\\s+(\\w+)\\s+(\\w+)\\s+(\\d+)\\s+(.*)\\s+" + pattern;
        //(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\S+)+\\s+(\\d+)\\s+(.+)\\s+(\\S+)
        String regex = "(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\S+)+\\s+(\\d+)\\s+(.+)\\s+(\\S+)";
        Pattern p = Pattern.compile(regex);
        Matcher matcher = null;
        BufferedReader reader = null;
        String strLine = null;
        try {
            reader = CommandReader.getReader(ip, cmd, 0, 0);
            if ((strLine = reader.readLine()) != null) {
                matcher = p.matcher(strLine);
                if (matcher.find()) {
                    currentAttribute = new FileAttribute(matcher.group(7), matcher.group(1), Integer.parseInt(matcher.group(2)), matcher.group(3), matcher.group(4), Long.parseLong(matcher.group(5)), 0L, matcher.group(6));
                }
            }
            return currentAttribute;
        } catch (IOException e) {
            logger.error("failed to reader file" + pattern, e);
            return null;
        }
    }

    /**
     *  得到一个目录中文件名匹配某个模式的，在time分钟内被修改过文件数据的所有文件
     * @param path
     *                文件目录
     * @param fileNameRegex
     *               文件名正则表达式
     * @param time
     *               可以认为是日志的采集周期
     * @param ip
     *               采集文件所在主机ip
     * @return
     *              返回所有被修改过的文件，如果没有返回null
     * @throws IOException
     */
    public static List<FileAttribute> getModifiedFiles(String path, String fileNameRegex, Long time, String ip) {
        //ls -lt |grep 'cicp.log*'|head -n `find /root/cicp/logs/  -name 'cicp.log*' -mmin -14|grep -v '^/root/cicp/logs/$'|wc -l`
        List<FileAttribute> modifiedFileList = new ArrayList<FileAttribute>();
        //默认给5分钟是因为我们默认采集周期是5分钟
        if (time == null) {
            time = 5L;
        }
        String cmd = "ls -lt " + path + "|grep '" + fileNameRegex + "' |head -n `find " + path + " -name '" + fileNameRegex + "' -mmin -" + time + " |grep -v '^" + path + "$' |wc -l`";
        logger.info(cmd);
        String regex = "(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\S+)+\\s+(\\d+)\\s+(.+)\\s+(\\S+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = null;
        BufferedReader reader = null;
        String strLine = null;
        try {
            reader = CommandReader.getReader(ip, cmd, 0, 0);
            while ((strLine = reader.readLine()) != null) {
                matcher = pattern.matcher(strLine);
                if (matcher.find()) {
                    FileAttribute fileAttribute = new FileAttribute(matcher.group(7), matcher.group(1), Integer.parseInt(matcher.group(2)), matcher.group(3), matcher.group(4), Long.parseLong(matcher.group(5)), 0L, matcher.group(6));
                    modifiedFileList.add(fileAttribute);
                }
            }
            return modifiedFileList.size() > 0 ? modifiedFileList : null;
        } catch (IOException e) {
            logger.error("failed to reader file" + fileNameRegex, e);
            return null;
        }
    }

    /**
     * 得到一个目录中文件名匹配某个模式的文件中最新的文件For Windows版
     *
     * @param path
     *            目录名
     * @param pattern
     *            文件名模式
     * @param ip
     *            主机的IP
     * @return 满足要求的文件的属性，或者当不存在这样的文件时NULL
     * @auther credible_zhang 2005-03-13
     */
    public static FileAttribute getNewestRemoteFileByPatternWin(String path, String pattern, String ip) {
        return null;
    }

    /**
     * 得到一个目录中匹配某个模式的一组文件属性
     *
     * @param fullFileName
     * @param ip
     * @return
     * @throws IOException
     */
    public static FileAttribute[] getAllNewestRemoteFileByPattern(String path, String pattern, String ip) {
        return null;
    }

    /**
     * 得到一个文件的属性
     *
     * @param fullFileName
     *            文件名，包含全路径
     * @param ip
     *            主机IP
     * @return 该文件的属性, 或文件不存在时NULL
     */
    public static FileAttribute getRemoteFile(String fullFileName, String ip) throws IOException {
        return null;
    }

    /**
     * 为一个文件生成临时文件名
     *
     * @param prefix
     *            前缀，一般标记临时文件的类别
     * @param fullPathStr
     *            源文件的全路径名
     * @param suffix
     *            后缀，其他要考虑的因素可以放到后缀中
     * @return 临时文件名
     */
    public static String constructTmpFileName(String prefix, String fullPathStr, String suffix) {
        return null;
    }

    public static String constructTmpFileName(String ip, String prefix, String fullPathStr, String suffix) {
        return null;
    }

    public static String getJmxXml(String urlStr, String ip, Integer port) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection connection = null;
        StringBuffer sb = new StringBuffer();
        String line;
        BufferedReader in = null;
        String username = null;
        String encoding = null;
        String passwd = null;
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getJmxValue(ip, port);
        //int maxConn = protocolParameter.getMaxConn();

        if (protocolParameter != null) {
            username = protocolParameter.getUserName();
            passwd = protocolParameter.getPwd();
            String userPassword = username + ":" + passwd;
            encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes());
        }
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(URL_CONN_TIME_OUT);//设置超时时间
            if (username != null) {
                connection.setDoOutput(true);
                connection.setRequestProperty("Authorization", "Basic " + encoding);
            }
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            while ((line = in.readLine()) != null) {
                if (line.contains("<!DOCTYPE")) {
                    continue;
                }
                sb.append(line + "\n");
            }
        } catch (Exception e) {
            logger.error("", e);
            throw e;
        } finally {

            IOUtils.closeQuietly(in);
            connection.disconnect();
        }
        return sb.toString();
    }

    public static String getHttpXml(String urlStr) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection connection = null;
        StringBuffer sb = new StringBuffer();
        String line;
        BufferedReader in = null;
        String username = null;
        String encoding = null;
        String passwd = null;
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getHttpValue(urlStr);
        if (protocolParameter != null) {
            username = protocolParameter.getUserName();
            passwd = protocolParameter.getPwd();
            String userPassword = username + ":" + passwd;
            encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes());
        }
        try {
            connection = (HttpURLConnection) url.openConnection();
            if (username != null) {
                connection.setDoOutput(true);
                connection.setRequestProperty("Authorization", "Basic " + encoding);
            }
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            while ((line = in.readLine()) != null) {
                if (line.contains("<!DOCTYPE")) {
                    continue;
                }
                sb.append(line + "\n");
            }
        } catch (Exception e) {
            logger.error("", e);
            throw e;
        } finally {
            in.close();
            connection.disconnect();
        }
        return sb.toString();
    }

    public static String constructTmpFileName(String prefix, String fullPathStr) {
        return constructTmpFileName(prefix, fullPathStr, null);
    }

}